home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / program / tcpdumpb.zip / libpcap / savefile.c < prev    next >
C/C++ Source or Header  |  1996-07-17  |  9KB  |  341 lines

  1. /*
  2.  * Copyright (c) 1993, 1994, 1995, 1996
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that: (1) source code distributions
  7.  * retain the above copyright notice and this paragraph in its entirety, (2)
  8.  * distributions including binary code include the above copyright notice and
  9.  * this paragraph in its entirety in the documentation or other materials
  10.  * provided with the distribution, and (3) all advertising materials mentioning
  11.  * features or use of this software display the following acknowledgement:
  12.  * ``This product includes software developed by the University of California,
  13.  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
  14.  * the University nor the names of its contributors may be used to endorse
  15.  * or promote products derived from this software without specific prior
  16.  * written permission.
  17.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  18.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  19.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  20.  */
  21. #ifndef lint
  22. static char rcsid[] =
  23.     "@(#)$Header: savefile.c,v 1.30 96/07/15 00:48:52 leres Exp $ (LBL)";
  24. #endif
  25.  
  26. /*
  27.  * savefile.c - supports offline use of tcpdump
  28.  *    Extraction/creation by Jeffrey Mogul, DECWRL
  29.  *    Modified by Steve McCanne, LBL.
  30.  *
  31.  * Used to save the received packet headers, after filtering, to
  32.  * a file, and then read them later.
  33.  * The first record in the file contains saved values for the machine
  34.  * dependent values so we can print the dump file on any architecture.
  35.  */
  36.  
  37. #include <sys/types.h>
  38. #include <sys/time.h>
  39.  
  40. #include <errno.h>
  41. #include <memory.h>
  42. #include <stdio.h>
  43. #include <stdlib.h>
  44. #include <unistd.h>
  45.  
  46. #include "pcap-int.h"
  47.  
  48. #include "gnuc.h"
  49. #ifdef HAVE_OS_PROTO_H
  50. #include "os-proto.h"
  51. #endif
  52.  
  53. #define TCPDUMP_MAGIC 0xa1b2c3d4
  54.  
  55. /*
  56.  * We use the "receiver-makes-right" approach to byte order,
  57.  * because time is at a premium when we are writing the file.
  58.  * In other words, the pcap_file_header and pcap_pkthdr,
  59.  * records are written in host byte order.
  60.  * Note that the packets are always written in network byte order.
  61.  *
  62.  * ntoh[ls] aren't sufficient because we might need to swap on a big-endian
  63.  * machine (if the file was written in little-end order).
  64.  */
  65. #define    SWAPLONG(y) \
  66. ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
  67. #define    SWAPSHORT(y) \
  68.     ( (((y)&0xff)<<8) | (((y)&0xff00)>>8) )
  69.  
  70. #define SFERR_TRUNC        1
  71. #define SFERR_BADVERSION    2
  72. #define SFERR_BADF        3
  73. #define SFERR_EOF        4 /* not really an error, just a status */
  74.  
  75. static int
  76. sf_write_header(FILE *fp, int linktype, int thiszone, int snaplen)
  77. {
  78.     struct pcap_file_header hdr;
  79.  
  80.     hdr.magic = TCPDUMP_MAGIC;
  81.     hdr.version_major = PCAP_VERSION_MAJOR;
  82.     hdr.version_minor = PCAP_VERSION_MINOR;
  83.  
  84.     hdr.thiszone = thiszone;
  85.     hdr.snaplen = snaplen;
  86.     hdr.sigfigs = 0;
  87.     hdr.linktype = linktype;
  88.  
  89.     if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
  90.         return (-1);
  91.  
  92.     return (0);
  93. }
  94.  
  95. static void
  96. swap_hdr(struct pcap_file_header *hp)
  97. {
  98.     hp->version_major = SWAPSHORT(hp->version_major);
  99.     hp->version_minor = SWAPSHORT(hp->version_minor);
  100.     hp->thiszone = SWAPLONG(hp->thiszone);
  101.     hp->sigfigs = SWAPLONG(hp->sigfigs);
  102.     hp->snaplen = SWAPLONG(hp->snaplen);
  103.     hp->linktype = SWAPLONG(hp->linktype);
  104. }
  105.  
  106. pcap_t *
  107. pcap_open_offline(char *fname, char *errbuf)
  108. {
  109.     register pcap_t *p;
  110.     register FILE *fp;
  111.     struct pcap_file_header hdr;
  112.     int linklen;
  113.  
  114.     p = (pcap_t *)malloc(sizeof(*p));
  115.     if (p == NULL) {
  116.         strcpy(errbuf, "out of swap");
  117.         return (NULL);
  118.     }
  119.  
  120.     memset((char *)p, 0, sizeof(*p));
  121.     /*
  122.      * Set this field so we don't close stdin in pcap_close!
  123.      */
  124.     p->fd = -1;
  125.  
  126.     if (fname[0] == '-' && fname[1] == '\0')
  127.         fp = stdin;
  128.     else {
  129.         fp = fopen(fname, "r");
  130.         if (fp == NULL) {
  131.             sprintf(errbuf, "%s: %s", fname, pcap_strerror(errno));
  132.             goto bad;
  133.         }
  134.     }
  135.     if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
  136.         sprintf(errbuf, "fread: %s", pcap_strerror(errno));
  137.         goto bad;
  138.     }
  139.     if (hdr.magic != TCPDUMP_MAGIC) {
  140.         if (SWAPLONG(hdr.magic) != TCPDUMP_MAGIC) {
  141.             sprintf(errbuf, "bad dump file format");
  142.             goto bad;
  143.         }
  144.         p->sf.swapped = 1;
  145.         swap_hdr(&hdr);
  146.     }
  147.     if (hdr.version_major < PCAP_VERSION_MAJOR) {
  148.         sprintf(errbuf, "archaic file format");
  149.         goto bad;
  150.     }
  151.     p->tzoff = hdr.thiszone;
  152.     p->snapshot = hdr.snaplen;
  153.     p->linktype = hdr.linktype;
  154.     p->sf.rfile = fp;
  155.     p->bufsize = hdr.snaplen;
  156.  
  157.     /* Align link header as required for proper data alignment */
  158.     /* XXX should handle all types */
  159.     switch (p->linktype) {
  160.  
  161.     case DLT_EN10MB:
  162.         linklen = 14;
  163.         break;
  164.  
  165.     case DLT_FDDI:
  166.         linklen = 13 + 8;    /* fddi_header + llc */
  167.         break;
  168.  
  169.     case DLT_NULL:
  170.     default:
  171.         linklen = 0;
  172.         break;
  173.     }
  174.  
  175.     p->sf.base = (u_char *)malloc(p->bufsize + BPF_ALIGNMENT);
  176.     p->buffer = p->sf.base + BPF_ALIGNMENT - (linklen % BPF_ALIGNMENT);
  177.     p->sf.version_major = hdr.version_major;
  178.     p->sf.version_minor = hdr.version_minor;
  179. #ifdef PCAP_FDDIPAD
  180.     /* XXX padding only needed for kernel fcode */
  181.     pcap_fddipad = 0;
  182. #endif
  183.  
  184.     return (p);
  185.  bad:
  186.     free(p);
  187.     return (NULL);
  188. }
  189.  
  190. /*
  191.  * Read sf_readfile and return the next packet.  Return the header in hdr
  192.  * and the contents in buf.  Return 0 on success, SFERR_EOF if there were
  193.  * no more packets, and SFERR_TRUNC if a partial packet was encountered.
  194.  */
  195. static int
  196. sf_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, int buflen)
  197. {
  198.     FILE *fp = p->sf.rfile;
  199.  
  200.     /* read the stamp */
  201.     if (fread((char *)hdr, sizeof(struct pcap_pkthdr), 1, fp) != 1) {
  202.         /* probably an EOF, though could be a truncated packet */
  203.         return (1);
  204.     }
  205.  
  206.     if (p->sf.swapped) {
  207.         /* these were written in opposite byte order */
  208.         hdr->caplen = SWAPLONG(hdr->caplen);
  209.         hdr->len = SWAPLONG(hdr->len);
  210.         hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec);
  211.         hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec);
  212.     }
  213.     /*
  214.      * We interchanged the caplen and len fields at version 2.3,
  215.      * in order to match the bpf header layout.  But unfortunately
  216.      * some files were written with version 2.3 in their headers
  217.      * but without the interchanged fields.
  218.      */
  219.     if (p->sf.version_minor < 3 ||
  220.         (p->sf.version_minor == 3 && hdr->caplen > hdr->len)) {
  221.         int t = hdr->caplen;
  222.         hdr->caplen = hdr->len;
  223.         hdr->len = t;
  224.     }
  225.  
  226.     if (hdr->caplen > buflen) {
  227.         /*
  228.          * This can happen due to Solaris 2.3 systems tripping
  229.          * over the BUFMOD problem and not setting the snapshot
  230.          * correctly in the savefile header.  If the caplen isn't
  231.          * grossly wrong, try to salvage.
  232.          */
  233.         static u_char *tp = NULL;
  234.         static int tsize = 0;
  235.  
  236.         if (tsize < hdr->caplen) {
  237.             tsize = ((hdr->caplen + 1023) / 1024) * 1024;
  238.             if (tp != NULL)
  239.                 free((u_char *)tp);
  240.             tp = (u_char *)malloc(tsize);
  241.             if (tp == NULL) {
  242.                 sprintf(p->errbuf, "BUFMOD hack malloc");
  243.                 return (-1);
  244.             }
  245.         }
  246.         if (fread((char *)tp, hdr->caplen, 1, fp) != 1) {
  247.             sprintf(p->errbuf, "truncated dump file");
  248.             return (-1);
  249.         }
  250.         memcpy((char *)buf, (char *)tp, buflen);
  251.  
  252.     } else {
  253.         /* read the packet itself */
  254.  
  255.         if (fread((char *)buf, hdr->caplen, 1, fp) != 1) {
  256.             sprintf(p->errbuf, "truncated dump file");
  257.             return (-1);
  258.         }
  259.     }
  260.     return (0);
  261. }
  262.  
  263. /*
  264.  * Print out packets stored in the file initialized by sf_read_init().
  265.  * If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
  266.  */
  267. int
  268. pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
  269. {
  270.     struct bpf_insn *fcode = p->fcode.bf_insns;
  271.     int status = 0;
  272.     int n = 0;
  273.  
  274.     while (status == 0) {
  275.         struct pcap_pkthdr h;
  276.  
  277.         status = sf_next_packet(p, &h, p->buffer, p->bufsize);
  278.         if (status) {
  279.             if (status == 1)
  280.                 return (0);
  281.             return (status);
  282.         }
  283.  
  284.         if (fcode == NULL ||
  285.             bpf_filter(fcode, p->buffer, h.len, h.caplen)) {
  286.             (*callback)(user, &h, p->buffer);
  287.             if (++n >= cnt && cnt > 0)
  288.                 break;
  289.         }
  290.     }
  291.     /*XXX this breaks semantics tcpslice expects */
  292.     return (n);
  293. }
  294.  
  295. /*
  296.  * Output a packet to the initialized dump file.
  297.  */
  298. void
  299. pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
  300. {
  301.     register FILE *f;
  302.  
  303.     f = (FILE *)user;
  304.     /* XXX we should check the return status */
  305.     (void)fwrite((char *)h, sizeof(*h), 1, f);
  306.     (void)fwrite((char *)sp, h->caplen, 1, f);
  307. }
  308.  
  309. /*
  310.  * Initialize so that sf_write() will output to the file named 'fname'.
  311.  */
  312. pcap_dumper_t *
  313. pcap_dump_open(pcap_t *p, char *fname)
  314. {
  315.     FILE *f;
  316.     if (fname[0] == '-' && fname[1] == '\0')
  317.         f = stdout;
  318.     else {
  319.         f = fopen(fname, "w");
  320.         if (f == NULL) {
  321.             sprintf(p->errbuf, "%s: %s",
  322.                 fname, pcap_strerror(errno));
  323.             return (NULL);
  324.         }
  325.     }
  326.     (void)sf_write_header(f, p->linktype, p->tzoff, p->snapshot);
  327.     return ((pcap_dumper_t *)f);
  328. }
  329.  
  330. void
  331. pcap_dump_close(pcap_dumper_t *p)
  332. {
  333.  
  334. #ifdef notyet
  335.     if (ferror((FILE *)p))
  336.         return-an-error;
  337.     /* XXX should check return from fclose() too */
  338. #endif
  339.     (void)fclose((FILE *)p);
  340. }
  341.